package com.duoduo.common.api.help;

import com.duoduo.common.api.constants.Constant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;

import java.lang.annotation.Annotation;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 上下文获取工具类
 */
public class SpringContextInnerUtil {
	
	private final static Logger log = LoggerFactory.getLogger(SpringContextInnerUtil.class);
	private static ApplicationContext applicationContext;
	private static Map<String, String> configMap = new ConcurrentHashMap<>();
	private static Map<String, Boolean> configMap2 = new ConcurrentHashMap<>();
	private static Map<String, Integer> configMap3 = new ConcurrentHashMap<>();
	private static Map<String, Object> configMap4 = new ConcurrentHashMap<>();
	
	static{
		try {
			// 因为配置中心有时候会在@Value注入之前使用，所以需要在这里提前加载一下
			Class.forName(Constant.duoduo_APOLLO_CLASSNAME);
			putConfigIfAbsent(Constant.CONFIGCENTER_IMPL, Constant.APOLLO); // 配置中心默认apollo实现
		} catch (ClassNotFoundException e) {
			try {
				Class.forName(Constant.APOLLO_CLASSNAME);
				putConfigIfAbsent(Constant.CONFIGCENTER_IMPL, Constant.APOLLO); // 配置中心默认apollo实现
			} catch (ClassNotFoundException e2) {
				// no-op
			}
		}
	}

	public static void setApplicationContext(ApplicationContext context) {
		if(applicationContext != null){
			return;
		}
		applicationContext = context;
	}

	public static <T> T getBean(Class<T> requiredType) {
		try{
			return applicationContext.getBean(requiredType);
		}catch(Exception e){
			log.error("no such bean: " + requiredType);
			return null;
		}
	}
	
	public static <T> T[] getBeans(Class<T> requiredType) {
		T[] beans = null;
		try{
			String[] names = applicationContext.getBeanNamesForType(requiredType);
			if((ArrayInnerUtil.isNotEmpty(names))){
				beans = ArrayInnerUtil.genericArray(requiredType, names.length);
				for (int i=0; i<names.length; i++) {
					beans[i] = applicationContext.getBean(names[i], requiredType);
				}
			}
			return beans;
		}catch(Exception e){
			log.error("no such bean: " + requiredType);
			return null;
		}
	}
	
	public static Object getBean(String beanId) {
		try{
			return applicationContext.getBean(beanId);
		}catch(Exception e){
			log.error("no such bean: " + beanId);
			return null;
		}
	}

	/**返回指定类型的bean
	 * @param beanId
	 * @param clazz
	 * @return 指定类型的bean实例；如果无法获取指定类型的bean，返回null
	 */
	public static <T> T getBean(String beanId, Class<T> clazz) {
		try{
			T bean = applicationContext.getBean(beanId, clazz);
			return bean;
		}catch(Exception e){
			log.error("no such bean: " + beanId);
			return null;
		}
	}

	public static Class<?> getBeanClass(String beanId) {
		Object bean = getBean(beanId);
		if(bean == null){
			return null;
		}
		return bean.getClass();
	}
	
	public static String[] getBeanNamesForAnnotation(Class<? extends Annotation> anno) {
		return applicationContext.getBeanNamesForAnnotation(anno);
	}
	
	public static <T> void putConfigIfAbsent(String key, T value){
		if(value instanceof Integer){
			configMap3.putIfAbsent(key, (Integer)value);
		}else if(value instanceof Boolean){
			configMap2.putIfAbsent(key, (Boolean)value);
		}else if(value instanceof String){
			configMap.putIfAbsent(key, (String)value);
		}else{
			configMap4.putIfAbsent(key, (Object)value);
		}
	}

	public static String get(String key) {
		return configMap.get(key);
	}
	
	public static Boolean getBoolean(String key) {
		return configMap2.get(key);
	}
	
	public static Integer getInteger(String key) {
		return configMap3.get(key);
	}
	
	public static Object getObject(String key) {
		return configMap4.get(key);
	}

	public static boolean containsBean(String beanName) {
		return applicationContext.containsBean(beanName);
	}

	/**注册bean
	 * @param beanName
	 * @param bean
	 */
	public static void registerSingleton(String beanName, Object bean) {
		ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
		ConfigurableListableBeanFactory beanFactory = configurableApplicationContext.getBeanFactory();
		beanFactory.registerSingleton(beanName, bean);
	}
	
	/**移除bean
	 * @param beanName
	 */
	public static void removeBeanDefinition(String beanName) {
		ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
		ConfigurableListableBeanFactory beanFactory = configurableApplicationContext.getBeanFactory();
		if(beanFactory instanceof DefaultListableBeanFactory){
			((DefaultListableBeanFactory)beanFactory).destroySingleton(beanName);
		}
	}
	
	/**注册bean定义
	 * @param beanName
	 * @param bean
	 */
	public static void registerBeanDefinition(String beanName, Class<?> clazz) {
		BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry) applicationContext;
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(clazz);
        beanFactory.registerBeanDefinition(beanName, beanDefinition);
	}
	
	/**执行一遍bean的autowired注解，因为registerSingleton时，不会执行依赖注入
	 * @param bean
	 */
	public static void autowireBean(Object bean){
		applicationContext.getAutowireCapableBeanFactory().autowireBean(bean);
	}
	
	/**获取spring的Environment
	 * @return
	 */
	public static Environment getEnvironment(){
		return applicationContext.getEnvironment();
	}

}